package com.cskaoyan.javase.oop1._6constructor;

/**
 * 构造器的引入
 * 创建一个教师类，有课程和年龄两个属性，行为是可以上课。
 * 现在我们需要创建以下对象：
 * 18岁的Java老师对象
 * 28岁的C++老师对象
 * 30岁的Python老师对象
 * ...
 * 按照之前我们的做法，需要先创建出对象，再进行成员变量的赋值。
 * 这样做如果只有一个两个对象还好，如果需要创建很多对象，就有点过于麻烦了。
 * 对象的属性，能不能"出厂"的时候就设定好呢？
 * 有这种需求时，就需要，构造方法（constructor，也叫构造器）来完成了。
 *
 * 构造器/构造方法的语法:
 * [访问权限修饰符] 类名(形参列表){
 *   // 构造方法体
 * }
 * 语法解释:
 *      1.访问权限修饰符我们还没有学习，这里我们默认它是public修饰的。
 *      2.类名的位置必须和当前类的类名完全一致。（类名是大驼峰的，这里也要大驼峰）
 *          注:构造器的名字必须和类名保持一致,而且构造器没有返回值类型,也不需要返回值,没有返回值
 *      3.形参列表可以为空，称之为无参构造方法，简称无参构造。当然也可以有参数，是为有参构造。
 *      4.构造方法的方法体和类中的成员方法的方法体,是类似的
 *          因为它们都有隐含的this传参,指向当前对象!!构造器当中是可以使用this关键字的.
 *
 * 构造器的作用:
 *    构造器是用来,在创建对象的过程中,给对象中的成员变量赋值用的.
 *      1.千万不要产生误解,不要认为构造器是用来创建对象的,
 *          创建对象是JVM完成的事情,和构造器本身没有关系
 *          构造器不过是在创建对象的过程中,给对象中的成员变量赋值用的.
 *
 *      2.构造器虽然是一个方法,但它是一个特殊的方法.这个方法不是由程序员自己去调用的
 *          而是在创建对象的过程中,由JVM去调用,然后完成成员变量的赋值的
 *          程序员没有办法来主动调用这个方法.
 *
 *      3.构造器虽然程序员无法主动调用,但是程序员可以指示JVM调用哪个构造器
 *          在创建对象的过程中,给成员变量赋值
 *          语法:
 *              new 类名(实参列表)
 *          这说明在Java中只要使用new关键字创建对象,一定会调用类的构造器
 *          具体调用哪个,用实参列表来判断,这说明一个类中可以有多个构造器,它们组成方法的重载
 *
 *      4.构造器的赋值作用:
 *          在一次创建对象的过程中,构造器的代码,构造器的赋值,永远是最后进行的!
 *          这说明,构造器的赋值一定是准确的,只要使用构造器赋值,那么最终成员变量的取值一定是参数中给出的值.
 *          注:
 *              构造器赋值的准确由标准格式的构造器保证,如果是乱写的构造器,那么就保证不了了
 *              标准格式的构造器(标准格式的构造器赋值)
 *              [访问权限修饰符] 类名/构造器名 (成员变量数据类型 成员变量名...){
 *                  this.成员变量名 = 成员变量名;
 *                  ....
 *              }
 *
 * 以上构造器的概念和作用讲清楚了
 * 接下来开始在类中定义构造器
 *      1.在Java中,任何一个类中,如果没有显式直接的提供一个构造器,那么编译器会在编译代码时,自动加上一个无参构造器,称之为默认无参
 *      格式:
 *      public 类名(){}
 *      默认无参是没有办法给成员变量赋值
 *
 *      注:
 *          但是如果类中存在任何一个构造器
 *          那么默认无参就不会再提供了
 *      建议:
 *          大家日常在写一个类的时候,如果这个类有创建对象的需求,建议手动加上默认无参,这是一个好习惯.
 *          当然也要具体情况具体对待.
 *
 *      2.要想主动使用构造器给成员变量赋值,需要使用有参构造器,标准格式:
 *        [访问权限修饰符] 类名/构造器名 (成员变量数据类型 成员变量名...){
 *          this.成员变量名 = 成员变量名;
 *          ....
 *        }
 *        标准格式构造器的赋值一定是准确的
 *        因为构造器的代码在创建对象的过程中
 *        是最后执行的
 *
 *
 * 注意事项:
 *      1.构造器是用来赋值的,而且是最后赋值的,它不是创建对象的.
 *      对象是JVM创建的
 *      实际上,在构造器执行的时候,对象早就创建完毕了
 *      执行构造器的代码,不过是完成创建对象,赋值的收尾工作.
 *
 *      2.构造器的作用就是赋值，那么不要在构造器中乱写代码。构造器最好就是标准格式，不要将业务代码写进去。
 *      当然如果成员变量的赋值，确实需要一个复杂的逻辑，建议提取出一个方法，然后在构造器中调用。
 *      尽量保证构造器的代码简洁性。
 *
 *
 *      3.构造器的书写,一般使用标准格式构造器就足够了.所以建议使用快捷键自动生成,不要手写.
 *      快捷键: alt + insert
 *
 *      4.类中多个构造器是方法的重载的关系.
 *          那么形参的名字不同,无法构造方法重载.
 *
 *      5.构造器和类加载
 *          new对象就会触发类加载
 *          但是某个类的类加载最多只有一次
 *          但是构造器的执行
 *              是new对象一次就会执行一次
 *
 * @since 09:26
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        t.age = 18;
        t.course = "JavaSE";
        t.teach();

        Teacher t2 = new Teacher();
        t2.course = "C++";
        t2.age = 28;
        t2.teach();
        System.out.println("------------------");
        // 使用有参构造器赋值
        Teacher t3 = new Teacher(38, "数学");
        t3.teach();

        Teacher t4 = new Teacher(48, "物理");
        t4.teach();
    }
}

class Teacher {
    int age = 88;
    String course = "语文";
    String name;

    public void teach() {
        System.out.println("我今年" + age + "岁,我教" + course);
    }

    // 默认无参
    public Teacher() {
    }

    // 写构造器给age,course赋值,是一个双参构造器
    public Teacher(int age, String course) {
        // init();
        this.course = course;
        this.age = age;
    }


    public Teacher(int age) {
        this.age = age;
    }

    public Teacher(String course) {
        this.course = course;
    }

    /*public Teacher(String name) {
        this.name = name;
    }*/

    public void init() {
    }

}